package com.karson.service.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.karson.common.config.rabbitmq.RabbitConfig;
import com.karson.common.config.redis.RedisConfig;
import com.karson.common.constants.BusinessConstants;
import com.karson.common.constants.Constants;
import com.karson.common.dto.rabbitmq.StatisticMessageDTO;
import com.karson.common.exception.AsmrException;
import com.karson.common.model.UserFavorite;
import com.karson.common.model.UserFavoriteRecord;
import com.karson.common.request.FavoriteRecordRequest;
import com.karson.common.request.PageParamRequest;
import com.karson.common.request.UserActionRequest;
import com.karson.common.request.UserFavoriteFolderRequest;
import com.karson.common.response.FavoriteAlbumResponse;
import com.karson.common.response.UserFavoriteFolderResponse;
import com.karson.common.util.RedisUtil;
import com.karson.common.vo.PageVo;
import com.karson.service.dao.AlbumInfoMapper;
import com.karson.service.dao.UserFavoriteRecordMapper;
import com.karson.service.service.UserActionService;
import com.karson.service.service.UserFavoriteService;
import com.karson.service.dao.UserFavoriteMapper;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
* @author ZKS
* @description 针对表【ar_user_favorite(用户收藏夹表)】的数据库操作Service实现
* @createDate 2025-09-04 14:08:51
*/
@Service
public class UserFavoriteServiceImpl extends ServiceImpl<UserFavoriteMapper, UserFavorite>
    implements UserFavoriteService{
    @Autowired
    private UserFavoriteMapper userFavoriteMapper;
    @Autowired
    private UserFavoriteRecordMapper userFavoriteRecordMapper;
    @Autowired
    private AlbumInfoMapper albumInfoMapper;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private UserActionService userActionService;



    /** Redis最多缓存200条数据 */
    private static final long CACHE_MAX_SIZE = 200;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<UserFavoriteFolderResponse> getFavFolder(Integer messageId) {
        // 当用户来查看收藏夹时，会先检测是否创建默认收藏夹（默认收藏夹，不再用户创建时生成，只有用户用到才生成）默认不可删除
        Integer uid = StpUtil.getLoginIdAsInt();
        LambdaQueryWrapper<UserFavorite> userFavQueryWrapper = new LambdaQueryWrapper<>();
        userFavQueryWrapper.eq(UserFavorite::getUid,uid);
        userFavQueryWrapper.eq(UserFavorite::getIsDefault,true);
        Long count = userFavoriteMapper.selectCount(userFavQueryWrapper);
        if (count <= 0){
            // 该用户还没有默认收藏夹
            //创建默认收藏夹
            UserFavorite userFavorite = new UserFavorite();
            userFavorite.setUid(uid);
            // 默认收藏不限容量
            userFavorite.setCapacity(-1);
            userFavorite.setName("默认收藏夹");
            userFavorite.setIsDefault(true);
            userFavoriteMapper.insert(userFavorite);
        }
        // 已有收藏夹
        return userFavoriteMapper.getFavFolder(uid);
    }

    @Override
    public UserFavoriteFolderResponse createFolder(UserFavoriteFolderRequest request) {
        Integer uid = StpUtil.getLoginIdAsInt();
        UserFavorite userFavorite = BeanUtil.copyProperties(request, UserFavorite.class);
        userFavorite.setUid(uid);
        userFavorite.setIsDefault(false);
        userFavorite.setCapacity(1000);
        userFavoriteMapper.insert(userFavorite);
        UserFavoriteFolderResponse userFavoriteFolderResponse = BeanUtil.copyProperties(userFavorite, UserFavoriteFolderResponse.class);
        userFavoriteFolderResponse.setFolderNum(0);
        return userFavoriteFolderResponse;
    }

    /**
     * 这是一个多收藏夹，用户不管选择那个收藏夹进行收藏都只算一次收藏
     * 当用户把作品从所有收藏夹中移出才会对收藏数量进行减少操作
     * @param request
     */
    @Override
    public void addFavorite(FavoriteRecordRequest request) {
        int uid = StpUtil.getLoginIdAsInt();
        String redisKey = RedisConfig.COUNT_KEY + BusinessConstants.BUSINESS_ALBUM + ":" + request.getMessageId();
        // 查出数据库已有的收藏
        LambdaQueryWrapper<UserFavoriteRecord> userFavoriteRecordWrapper = new LambdaQueryWrapper<>();
        userFavoriteRecordWrapper.eq(UserFavoriteRecord::getMessageId, request.getMessageId());
        userFavoriteRecordWrapper.eq(UserFavoriteRecord::getUid, uid);
        userFavoriteRecordWrapper.eq(UserFavoriteRecord::getStatus, true);
        List<UserFavoriteRecord> favoriteRecords = userFavoriteRecordMapper.selectList(userFavoriteRecordWrapper);

        // 数据库已有 folderIds
        Set<Integer> dbFolderIds = favoriteRecords.stream()
                .map(UserFavoriteRecord::getFolderId)
                .collect(Collectors.toSet());
        String userFavKey = RedisConfig.ALBUM_USER_FAV;
        //构建用户行为消息体
        UserActionRequest userActionRequest = new UserActionRequest();
        userActionRequest.setActionType(Constants.ACTION_FAV);
        userActionRequest.setType(BusinessConstants.BUSINESS_ALBUM);
        // 业务id = 实体 id 就说明操作的就是这个实体
        userActionRequest.setMessageId(request.getMessageId());
        // 请求的 folderIds为空删除状态信息，缓存数量
        if (request.getFolderIds() == null || request.getFolderIds().isEmpty()){
            if (redisUtil.exists(redisKey)) {
                userActionService.recordUserAction(userActionRequest);
            }
        }
        Set<Integer> reqFolderIds = new HashSet<>(request.getFolderIds());

        // 1. 数据库有但请求没有 -> 删除
        List<UserFavoriteRecord> toDeleteRecords = favoriteRecords.stream()
                .filter(record -> !reqFolderIds.contains(record.getFolderId()))
                .toList();
        for (UserFavoriteRecord record : toDeleteRecords) {
            record.setStatus(false);
            userFavoriteRecordMapper.updateById(record);

            String key = RedisConfig.ZSET_FAV_KEY + uid + ":" + record.getFolderId();
            // 删除原缓存
            if (redisUtil.exists(key)) {
                redisUtil.deleteZSet(key);
            }
        }

        // 2. 请求有但数据库没有 -> 新增
        List<Integer> toInsertFolderIds = reqFolderIds.stream()
                .filter(folderId -> !dbFolderIds.contains(folderId))
                .toList();

        List<UserFavoriteRecord> insertList = new ArrayList<>();
        toInsertFolderIds.forEach(folderId -> {
            // 全局自增序列
            long score = redisUtil.incrAndCreate(RedisConfig.FAV_GLOBAL_SEQ_KEY);
            UserFavoriteRecord userFavoriteRecord = new UserFavoriteRecord();
            userFavoriteRecord.setUid(uid);
            userFavoriteRecord.setFolderId(folderId);
            userFavoriteRecord.setMessageId(request.getMessageId());
            userFavoriteRecord.setSort((int) score);
            userFavoriteRecord.setStatus(true);
            insertList.add(userFavoriteRecord);
        });
        // 如果随便某一个收藏夹中有这个实体的记录就证明已经收藏
        if (request.getFolderIds() != null && !request.getFolderIds().isEmpty()){
            if (!redisUtil.sIsMember(userFavKey+ uid,request.getMessageId())){
                userActionService.recordUserAction(userActionRequest);
            }
        }
        if (!insertList.isEmpty()) {
            userFavoriteRecordMapper.insertBatch(insertList);
        }

        // 新增缓存，用 Redis 全局自增序列替代 now
        toInsertFolderIds.forEach(folderId -> {
            String key = RedisConfig.ZSET_FAV_KEY + uid + ":" + folderId;
            // 删除原缓存
            if (redisUtil.exists(key)) {
                redisUtil.deleteZSet(key);
            }
        });
    }

    @Override
    public PageVo<FavoriteAlbumResponse> getFavorite(PageParamRequest pageParams, Integer folderId) {
        int uid = StpUtil.getLoginIdAsInt();
        String key = RedisConfig.ZSET_FAV_KEY + uid + ":" + folderId;

        // 1. 查询数据库总数
        LambdaQueryWrapper<UserFavoriteRecord> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserFavoriteRecord::getFolderId, folderId)
                .eq(UserFavoriteRecord::getUid, uid)
                .eq(UserFavoriteRecord::getStatus, true);
        long count = userFavoriteRecordMapper.selectCount(wrapper);

        int startIndex = (pageParams.getCurrent() - 1) * pageParams.getSize();
        int endIndex = pageParams.getCurrent() * pageParams.getSize() - 1;

        PageVo<FavoriteAlbumResponse> albumPage = new PageVo<>();
        albumPage.setCurrent(pageParams.getCurrent());
        albumPage.setSize(pageParams.getSize());
        albumPage.setTotal(count);
        albumPage.setPages((int) ((count + pageParams.getSize() - 1) / pageParams.getSize()));

        // 2. 超过缓存范围，直接查数据库，不写缓存
        if (startIndex >= CACHE_MAX_SIZE) {
            List<UserFavoriteRecord> dbRecords = userFavoriteRecordMapper.selectPageList(folderId, startIndex, pageParams.getSize());
            List<Integer> messageIds = dbRecords.stream()
                    .map(UserFavoriteRecord::getMessageId)
                    .toList();
            List<FavoriteAlbumResponse> records = albumInfoMapper.getPageListById(messageIds);
            albumPage.setRecords(records);
            return albumPage;
        }

        // 3. 尝试从缓存获取
        Set<Object> cacheSet = redisUtil.getPage(key, pageParams.getCurrent(), pageParams.getSize());
        if (cacheSet != null && !cacheSet.isEmpty()) {
            List<FavoriteAlbumResponse> albumInfos = cacheSet.stream()
                    .filter(obj -> obj instanceof FavoriteAlbumResponse)
                    .map(obj -> (FavoriteAlbumResponse) obj)
                    .toList();
            albumPage.setRecords(albumInfos);
            return albumPage;
        }

        // 4. 缓存未命中，从数据库查询前 CACHE_MAX_SIZE 条数据并写回缓存
        int fetchSize = (int) Math.min(CACHE_MAX_SIZE, count);
        List<UserFavoriteRecord> dbRecords = userFavoriteRecordMapper.selectPageList(folderId, 0, fetchSize);

        Map<Integer, Integer> messageIdToSort = dbRecords.stream()
                .collect(Collectors.toMap(UserFavoriteRecord::getMessageId, UserFavoriteRecord::getSort));

        List<Integer> messageIds = dbRecords.stream()
                .map(UserFavoriteRecord::getMessageId)
                .toList();
        if(messageIds.isEmpty()){
            albumPage.setRecords(null);
            return albumPage;
        }
        List<FavoriteAlbumResponse> records = albumInfoMapper.getPageListById(messageIds);

        // 写缓存
        records.forEach(album -> {
            Integer sort = messageIdToSort.get(album.getAlbumId());
            if (sort != null) {
                redisUtil.zAdd(key, album, sort);
            }
        });

        // 控制缓存长度
        long size = redisUtil.size(key);
        if (size > CACHE_MAX_SIZE) {
            redisUtil.removeRange(key, 0, size - CACHE_MAX_SIZE - 1);
        }
        redisUtil.expire(key, RedisConfig.CACHE_TTL_SECONDS);

        // 5. 返回当前页数据  +1 因为 subList 是 [from, to)
        int toIndex = Math.min(endIndex + 1, records.size());
        startIndex  = toIndex <= startIndex ? 0 : startIndex;
        albumPage.setRecords(records.subList(startIndex, toIndex));

        return albumPage;
    }

    @Override
    public Boolean updateFolder(UserFavoriteFolderRequest request) {
        UserFavorite userFavorite = userFavoriteMapper.selectById(request.getId());
        if (userFavorite == null) {
            throw new AsmrException("您修改的文件夹不存在");
        }
        userFavorite.setName(request.getName());
        userFavorite.setDescription(request.getDescription());
        userFavorite.setCoverUrl(request.getCoverUrl());
        userFavoriteMapper.updateById(userFavorite);
        return true;
    }

    @Override
    public List<Integer> getFavoriteFolder(Integer messageId) {
        int uid = StpUtil.getLoginIdAsInt();
        LambdaQueryWrapper<UserFavoriteRecord> favoriteRecordLambdaQueryWrapper = new LambdaQueryWrapper<>();
        favoriteRecordLambdaQueryWrapper.eq(UserFavoriteRecord::getUid, uid);
        favoriteRecordLambdaQueryWrapper.eq(UserFavoriteRecord::getMessageId, messageId);
        favoriteRecordLambdaQueryWrapper.eq(UserFavoriteRecord::getStatus, true);
        List<UserFavoriteRecord> userFavoriteRecords = userFavoriteRecordMapper.selectList(favoriteRecordLambdaQueryWrapper);
        return userFavoriteRecords.stream().map(UserFavoriteRecord::getFolderId).toList();
    }

}




